#include "Tcp_Connection.hpp"
#include "Message.hpp"
#include <map>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "Config.hpp"
#include "Logger.h"



const int c_Time_out	= 1;
const int c_SensorUpdate = 1;
bool Interactive = true;

class Server_End : public Tcp_Connection
{

	typedef boost::shared_ptr< Message > MsgPointer;


	bool 	m_AckMapInUse;
	bool	m_EntityAckRecieved;
	int		m_id ;

	boost::asio::deadline_timer m_AckTimeoutTimer;
	boost::asio::deadline_timer m_SensorUpdateTimer;
	std::map< int, MsgPointer > m_NonAckMessages;
	Logger& LOGGER;
	DataType	m_Type; // What data does this sensor send.


public:
	typedef boost::shared_ptr<Server_End> ServerEndPointer;
	

Server_End(boost::asio::io_service& io_service, Logger& logg , DataType dtype): Tcp_Connection( io_service ),
												m_AckMapInUse( false ),
												m_EntityAckRecieved( false ),
												m_id( 0 ),
												m_AckTimeoutTimer( io_service ),
												m_SensorUpdateTimer( io_service ),
												LOGGER( logg )

{
	m_Type = dtype;

}

void InitializeConnection()
{

	MsgPointer msg( new Message() );
	msg->ID 		= "0";
	msg->m_MsgType	= REQ;
	msg->m_DataType	= CSS;
	msg->m_action	= ENTITY;
	msg->data		= "Sensor";

	PostMessage( msg );
	IssueWait();
}

void LockAckMap()
{
	while ( m_AckMapInUse )
		{
			sleep( 0.1 );
		}
	m_AckMapInUse = true;
}

void UnLockAckMap()
{

	m_AckMapInUse = false;
}


void HandelTimeout( const boost::system::error_code& err )
{


	typedef std::map< int, MsgPointer >::iterator _MsgIterator;
	std::vector< _MsgIterator > MsgsToDelete;

	//std::cout<<"HandleTimeout: Entering."<<std::endl;
	if( err != boost::asio::error::operation_aborted )
	{
		LockAckMap();
		//std::cout<<"HandleTimeout: Lock acquired"<<std::endl;
		_MsgIterator MsgIterator = m_NonAckMessages.begin() ;
		if( m_NonAckMessages.size() > 0 ){

			for( ; MsgIterator != m_NonAckMessages.end() ; MsgIterator++ )
			{
				if( MsgIterator->second->IsTimedOut( c_Time_out ) ){
					if( MsgIterator->second->m_bAcknowledged == false ){
						std::cout<<"Retry Number "<<MsgIterator->second->m_resndCount<<std::endl;
						Send( MsgIterator->second->Encode() );
						MsgIterator->second->UpdateResend();
					}
					else{
						std::cout<<"Message Acknowledged"<<MsgIterator->second->Encode()<<std::endl;
						MsgsToDelete.push_back( MsgIterator );
					}
				}
				else{
					std::cout<<"Message"<<MsgIterator->second->Encode()<<" is not timed out yet"<<std::endl;
				}
			}

			//Now delete all the acknowledged messages from the list.
			std::vector< _MsgIterator >::iterator VecMessages = MsgsToDelete.begin();
			for( ; VecMessages < MsgsToDelete.end() ; VecMessages++ ){
				m_NonAckMessages.erase( *VecMessages  );
			}
	}
	else{
//		std::cout<<"HandleTimeouts::m_NonAckMessages.size() "<<m_NonAckMessages.size()<<std::endl;
//		std::cout<<"No non-ack Messaeges"<<std::endl;
	}

		UnLockAckMap();
		IssueWait();
	}
	else{

		if( err ==  boost::asio::error::operation_aborted )	{
					std::cout<<"Timer Interrupted "<< std::endl;
		}
	}
//	std::cout<<"HandleTimeout: Leaving."<<std::endl;
}

void IssueWait()
{

	m_AckTimeoutTimer.expires_from_now(  boost::posix_time::seconds( c_Time_out ) );
	m_AckTimeoutTimer.async_wait( boost::bind(	&Server_End::HandelTimeout,
												this,
												boost::asio::placeholders::error ) );
}
void SendSensorUpdateTimeout( const boost::system::error_code& err )
{
	//Pick random value between 0 and 90.
	std::string degree = Convert::T_to_string( rand()%91 );

	if( err !=  boost::asio::error::operation_aborted )
	{
		LOGGER<<"Server_End::SendSensorUpdateTimeout\n";

		if( Interactive ){
			LOGGER<<"Enter a value to send \n";
			std::cin>>degree;}

		SendSensorUpdate( degree );
		IssueSensorUpdate();
	}
	else
	{
		if( err ==  boost::asio::error::operation_aborted )
		{
			//std::cout<<"SendSensorUpdateTimeout Interrupted "<<std::endl;
			LOGGER<<"SendSensorUpdateTimeout Interrupted \n";
		}
	}
}

void IssueSensorUpdate()
{
	std::cout<<"void IssueSensorUpdate()\n";
	m_SensorUpdateTimer.expires_from_now(  boost::posix_time::seconds( c_SensorUpdate ) );
	m_SensorUpdateTimer.async_wait( boost::bind(	&Server_End::SendSensorUpdateTimeout,
													this,
													boost::asio::placeholders::error ) );
}

void SendSensorUpdate( std::string degree )
{
	MsgPointer msg( new Message );
	m_id++;
	std::string val;

	val = Convert::T_to_string( m_id );
	msg->ID 		= val;
	msg->m_MsgType	= REQ;
	msg->m_DataType	= m_Type;
	msg->m_action	= SUBMIT;
	msg->data		= degree;

	PostMessage( msg  );

}

void PostMessage( MsgPointer Msg )
{

	if( false == m_EntityAckRecieved && Msg->m_action != ENTITY )
	{
		std::cout<<"Error, trying to send message before receiving Acknowledgment , Ignoring message"<<std::endl;
	}
	else
	{
		bool res = Send( Msg->Encode() );
		if( res == true )
		{
			m_NonAckMessages[ atoi( Msg->ID.c_str() ) ] = Msg;
			std::cout<<"PostMeeeage:: m_NonAckMessages.size() "<<m_NonAckMessages.size()<<std::endl;
		}
		else
		{
			std::cout<<"PostMessage: Error in socket connection, closing handles"<<std::endl;
			boost::system::error_code err =  boost::asio::error::operation_aborted;
			m_SensorUpdateTimer.cancel( err );
			m_AckTimeoutTimer.cancel(err );
			socket_.close();
		}
	}

}

void HandleAck( Message& ReceievedMessage )
{
	if(		ReceievedMessage.m_action == ENTITY
			&& ReceievedMessage.ID == "0"
			&& m_EntityAckRecieved == false )
	{
		std::cout<<"Received Acknoledegem for bind"<<std::endl;
		m_EntityAckRecieved = true;
		LockAckMap();
		m_AckMapInUse = true;
		m_NonAckMessages[ 0 ]->m_bAcknowledged = true;
		UnLockAckMap();

		//start sending updates:
		IssueSensorUpdate();
	}
	else
	{
		//Make sure that the message is in the non acknowledged messages map.
		LockAckMap();
		std::map<int, MsgPointer>::iterator  M	=	m_NonAckMessages.find( atoi( ReceievedMessage.ID.c_str() ) );
		if( M != m_NonAckMessages.end() )
		{
			M->second->m_bAcknowledged			=	true;
		}
		else
		{
			std::cerr<<"Error, receiving Acknowledgment Message for a message that was never sent or was acknowledged before, ignoring "<<std::endl;
		}
		UnLockAckMap();
	}

}

void Recv_Handler(  const boost::system::error_code& error, // Result of operation.
						std::size_t bytes_transferred           // Number of bytes received.
					  )
	{
		if( !error )
			{
				std::cout<<"Sensor::Recv_Handler \n";
				Message ReceievedMessage;
				std::string MsgBuf = buf;
				if( ReceievedMessage.Decode( MsgBuf ) )
				{
					switch( ReceievedMessage.m_MsgType )
					{
						case RES:
							//sensor shouldn't be receiving a REQ, it only receives Acknoledgements.
							break;

						case REQ:
							//sensor shouldn't be receiving a REQ.
							break;
						case ACK:
							HandleAck( ReceievedMessage );
							break;
						default:
							std::clog<<"Error, Unidentified Message type"<<std::endl;
							break;
					}
				}
				else
				{
					std::clog<<"Error, Message buffer failed to decode"<<std::endl;
					std::clog<<"Message is "<< MsgBuf<<std::endl;
				}
				Receieve();
			}
			else
			{
				std::cerr<<"Error , closing connection \n";
				socket_.close();
			}
	}


	bool Handle_Send( const boost::system::error_code& error, size_t bytes_transferred )
	{
		return true;
	}

	//Receives a message and sends an Ack for that message.
	bool SendAck( Message m )
	{
		return true;
	};

	bool HandlePull( Message Msg )
	{
		return true;
	}

};





